package site.edody.dframe.websocket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.HashMap;
import java.util.Map;

/**
 * DFrame WebSocket 服务器管理器
 * @author Dody
 */
public class DFrameWebSocketManager {

    private static final Logger log = LoggerFactory.getLogger(DFrameWebSocketManager.class);

    private final DFrameWebSocketProperties webSocketProperties;
    private final DFrameWebSocketSessionCache sessionCache;
    private final DFrameWebSocketDataCache dataCache;
    private final DFrameDefaultWebSocketListener defaultWebSocketListener;

    @Autowired
    private ApplicationContext applicationContext;

    private final Map<String, DFrameWebSocketServer> servers = new HashMap<>();

    public DFrameWebSocketManager(
            DFrameWebSocketProperties webSocketProperties,
            DFrameWebSocketSessionCache sessionCache,
            DFrameWebSocketDataCache dataCache,
            DFrameDefaultWebSocketListener defaultWebSocketListener) {
        this.webSocketProperties = webSocketProperties;
        this.sessionCache = sessionCache;
        this.dataCache = dataCache;
        this.defaultWebSocketListener = defaultWebSocketListener;
    }

    @PostConstruct
    public void init() {
        log.info("开始初始化 DFrame WebSocket 服务器...");

        // 诊断日志：检查配置是否加载
        if (webSocketProperties == null) {
            log.error("WebSocketProperties 为 null，配置未正确加载");
            return;
        }

        log.info("WebSocketProperties 加载成功: {}", webSocketProperties.getClass().getName());

        if (webSocketProperties.getServers() == null) {
            log.warn("webSocketProperties.getServers() 返回 null");
            return;
        }

        if (webSocketProperties.getServers().isEmpty()) {
            log.warn("没有配置任何 DFrame WebSocket 服务器，请检查 application.yml 配置");
            log.info("当前配置的服务器数量: 0");
            return;
        }

        log.info("找到 {} 个配置的 WebSocket 服务器", webSocketProperties.getServers().size());

        webSocketProperties.getServers().forEach((serverName, config) -> {
            log.info("正在初始化服务器: {} -> 端口: {}, 监听器: {}",
                    serverName, config.getPort(), config.getListener());

            try {
                DFrameWebSocketListener listener = createListener(config.getListener());
                DFrameWebSocketServer server = new DFrameWebSocketServer(
                        serverName, config.getPort(), listener, sessionCache, dataCache
                );
                server.start();
                servers.put(serverName, server);
                log.info("成功启动 DFrame WebSocket 服务器: {} 在端口: {}", serverName, config.getPort());
            } catch (Exception e) {
                log.error("启动 DFrame WebSocket 服务器失败: {}", serverName, e);
            }
        });

        log.info("DFrame WebSocket 服务器初始化完成，成功启动 {} 个服务器", servers.size());
    }

    @PreDestroy
    public void destroy() {
        log.info("正在关闭 {} 个 DFrame WebSocket 服务器", servers.size());
        servers.forEach((name, server) -> {
            try {
                server.stop();
                log.info("已停止 DFrame WebSocket 服务器: {}", name);
            } catch (Exception e) {
                log.error("停止 DFrame WebSocket 服务器时出错: {}", name, e);
            }
        });
    }

    private DFrameWebSocketListener createListener(String listenerClassName) {
        log.debug("创建监听器: {}", listenerClassName);

        if (listenerClassName == null || listenerClassName.trim().isEmpty()) {
            log.info("使用默认 DFrame WebSocket 监听器");
            return defaultWebSocketListener;
        }

        try {
            Class<?> listenerClass = Class.forName(listenerClassName);

            // 优先从 Spring 容器中获取 Bean
            String[] beanNames = applicationContext.getBeanNamesForType(listenerClass);
            if (beanNames.length > 0) {
                // 使用第一个找到的 Bean
                DFrameWebSocketListener listener = (DFrameWebSocketListener) applicationContext.getBean(beanNames[0]);
                log.info("从 Spring 容器获取监听器: {} (Bean名称: {})", listenerClassName, beanNames[0]);
                return listener;
            } else {
                // 如果容器中没有，尝试按名称获取（处理 @Component 注解的情况）
                try {
                    String simpleName = listenerClass.getSimpleName();
                    String beanName = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
                    if (applicationContext.containsBean(beanName)) {
                        DFrameWebSocketListener listener = (DFrameWebSocketListener) applicationContext.getBean(beanName);
                        log.info("从 Spring 容器按名称获取监听器: {}", beanName);
                        return listener;
                    }
                } catch (Exception e) {
                    log.debug("按名称获取 Bean 失败，尝试直接实例化");
                }

                // 最后尝试直接实例化（这种情况下 @Autowired 不会生效）
                DFrameWebSocketListener listener = (DFrameWebSocketListener) listenerClass.getDeclaredConstructor().newInstance();

                // 尝试手动注入依赖
                try {
                    applicationContext.getAutowireCapableBeanFactory().autowireBean(listener);
                    log.info("手动注入依赖并实例化监听器: {}", listenerClassName);
                } catch (Exception e) {
                    log.warn("手动注入依赖失败，监听器中的 @Autowired 将不会生效: {}", listenerClassName);
                }

                return listener;
            }
        } catch (ClassNotFoundException e) {
            log.warn("监听器类未找到: {}, 使用默认监听器", listenerClassName);
            return defaultWebSocketListener;
        } catch (Exception e) {
            log.error("创建监听器失败: {}", listenerClassName, e);
            return defaultWebSocketListener;
        }
    }

    public DFrameWebSocketServer getServer(String serverName) {
        return servers.get(serverName);
    }

    public Map<String, DFrameWebSocketServer> getServers() {
        return new HashMap<>(servers);
    }

    public int getServerCount() {
        return servers.size();
    }

    public DFrameWebSocketDataCache getDataCache() {
        return dataCache;
    }

    public DFrameWebSocketSessionCache getSessionCache() {
        return sessionCache;
    }
}